
class Circle {
	constructor({ origin, speed, color, angle, context }) {
		this.origin = origin
		this.position = { ...origin }
		this.color = color
		this.speed = speed
		this.angle = angle
		this.context = context
		this.renderCount = 0
	}

	draw() {
		this.context.fillStyle = this.color
		this.context.beginPath()
		this.context.arc(this.position.x, this.position.y, 2, 0, Math.PI * 2)
		this.context.fill()
	}

	move() {
		this.position.x = (Math.sin(this.angle) * this.speed) + this.position.x
		this.position.y = (Math.cos(this.angle) * this.speed) + this.position.y + (this.renderCount * 0.3)
		this.renderCount++
	}
}

class Boom {
	constructor({ origin, context, circleCount = 10, area }) {
		this.origin = origin
		this.context = context
		this.circleCount = circleCount
		this.area = area
		this.stop = false
		this.circles = []
	}

	randomArray(range) {
		const length = range.length
		const randomIndex = Math.floor(length * Math.random())
		return range[randomIndex]
	}

	randomColor() {
		const range = ['8', '9', 'A', 'B', 'C', 'D', 'E', 'F']
		return '#' + this.randomArray(range) + this.randomArray(range) + this.randomArray(range) + this.randomArray(range) + this.randomArray(range) + this.randomArray(range)
	}

	randomRange(start, end) {
		return (end - start) * Math.random() + start
	}

	init() {
		for (let i = 0; i < this.circleCount; i++) {
			const circle = new Circle({
				context: this.context,
				origin: this.origin,
				color: this.randomColor(),
				angle: this.randomRange(Math.PI - 1, Math.PI + 1),
				speed: this.randomRange(1, 6)
			})
			this.circles.push(circle)
		}
	}

	move() {
		this.circles.forEach((circle, index) => {
			if (circle.position.x > this.area.width || circle.position.y > this.area.height) {
				return this.circles.splice(index, 1)
			}
			circle.move()
		})
		if (this.circles.length == 0) {
			this.stop = true
		}
	}

	draw() {
		this.circles.forEach(circle => circle.draw())
	}
}

class CursorSpecialEffects {
	constructor() {
		this.computerCanvas = document.createElement('canvas')
		this.renderCanvas = document.createElement('canvas')

		this.computerContext = this.computerCanvas.getContext('2d')
		this.renderContext = this.renderCanvas.getContext('2d')

		this.globalWidth = window.innerWidth
		this.globalHeight = window.innerHeight

		this.booms = []
		this.running = false
	}

	handleMouseDown(e) {
		const boom = new Boom({
			origin: { x: e.clientX, y: e.clientY },
			context: this.computerContext,
			area: {
				width: this.globalWidth,
				height: this.globalHeight
			}
		})
		boom.init()
		this.booms.push(boom)
		this.running || this.run()
	}

	handlePageHide() {
		this.booms = []
		this.running = false
	}

	init() {
		const style = this.renderCanvas.style
		style.position = 'fixed'
		style.top = style.left = 0
		style.zIndex = '999999999999999999999999999999999999999999'
		style.pointerEvents = 'none'

		style.width = this.renderCanvas.width = this.computerCanvas.width = this.globalWidth
		style.height = this.renderCanvas.height = this.computerCanvas.height = this.globalHeight

		document.body.append(this.renderCanvas)

		window.addEventListener('mousedown', this.handleMouseDown.bind(this))
		window.addEventListener('pagehide', this.handlePageHide.bind(this))
	}

	run() {
		this.running = true
		if (this.booms.length == 0) {
			return this.running = false
		}

		requestAnimationFrame(this.run.bind(this))

		this.computerContext.clearRect(0, 0, this.globalWidth, this.globalHeight)
		this.renderContext.clearRect(0, 0, this.globalWidth, this.globalHeight)

		this.booms.forEach((boom, index) => {
			if (boom.stop) {
				return this.booms.splice(index, 1)
			}
			boom.move()
			boom.draw()
		})
		this.renderContext.drawImage(this.computerCanvas, 0, 0, this.globalWidth, this.globalHeight)
	}
}

const cursorSpecialEffects = new CursorSpecialEffects()
cursorSpecialEffects.init()